#include <stdio.h>
#include "UpperLower.h"
#include "image.h"
#include "offsets.h"
#include "parameters.h"
#include "my_structs.h"

struct Result MaxResult;
int TotalHits;

void ClearTable() {
  int i;
  for (i=0; i<64; i++) {
    Table[i] = 0;
  }
  BelowTableCount = 0;
}

void BuildTable(x,y,t_num)
     int x;
     int y;
     int t_num;
{
  int tableIndex, imageIndex, targetIndex, x_offset, y_offset, x_template,
    y_template, x_image, y_image;
  int i,j,k;
  
  x_offset = x - 16;
  y_offset = y - 16;
  
  for (i=0; i<TargetPixelCount[t_num]; i++) {
    x_template = TargetIndex[t_num][i] % 32;
    y_template = TargetIndex[t_num][i] / 32;
    
    x_image = x_template + x_offset;
    y_image = y_template + y_offset;
    
    imageIndex = y_image * 64 + x_image;
    
    /* test image pixel vs. lower */
    tableIndex = 31 + Lower[t_num][i] - Image[imageIndex];
    if (tableIndex < 0) BelowTableCount++;
    if ((tableIndex < 64) && (tableIndex >= 0)) Table[tableIndex]++;
    
    /* test image pixel vs. upper */
    tableIndex = 31 + Upper[t_num][i] - Image[imageIndex];
    if (tableIndex < 0) BelowTableCount--;
    if ((tableIndex < 64) && (tableIndex >= 0)) Table[tableIndex]--;
  }
}

void SearchTable() {
  int i;
  int currentSum, maxTargetSumIndex, maxTargetSum, newAlpha;
  
  currentSum = BelowTableCount;
  maxTargetSumIndex = -1;
  maxTargetSum = 0;

  for (i=0; i<64; i++) {
    currentSum += Table[i];
    if (currentSum > maxTargetSum) {
      maxTargetSum = currentSum;
      maxTargetSumIndex = i;
    }
  }

  newAlpha = maxTargetSumIndex - 31;

  /* fill in CurResult fields */
  CurResult.TargetCount = maxTargetSum;
  CurResult.IndexOfMax = newAlpha;
}
  
    
void ComputeSurroundSum(x_loc, y_loc, t_num)
     int x_loc;
     int y_loc;
     int t_num;
{
  int threshold, surroundSum, imageIndex, x_offset, y_offset, 
    x_template, y_template, x_image, y_image;
  int i;

  surroundSum = 0;
  
  threshold = SurroundUpperClipping - CurResult.IndexOfMax;

  x_offset = x_loc - 16;
  y_offset = y_loc - 16;
  
  for (i=0; i<SurroundPixelCount[t_num]; i++) {
     x_template = SurroundIndex[t_num][i] % 32;
     y_template = SurroundIndex[t_num][i] / 32;

     x_image = x_template + x_offset;
     y_image = y_template + y_offset;

     imageIndex = (y_image * 64 + x_image) + 4096;

     if (Image[imageIndex] < threshold) surroundSum++;

     CurResult.SurroundCount = surroundSum;
  }
}


void ExecuteOneLocation(x, y, t_num)
     int x;
     int y;
     int t_num;
{
  /* 0. Initialize */
  ClearTable();
  
  /* 1. build the table */
  BuildTable(x,y);

  /* 2. search the table for the max */
  SearchTable();
  
  /* 3. check target count threshold */
  if (CurResult.TargetCount >= TargetThreshold[t_num]) {
    
    /* 4. compute surround sum */
    ComputeSurroundSum(x,y,t_num);
  
    /* 5. check surround count theshold */
    if (CurResult.SurroundCount >= SurroundThreshold[t_num]) {
      
      /* 6. compute combined score */
      ComputeCombinedScore(t_num);
    }
  }
}
      
      
void UpdateBestScore() {
  BestResult.hit = CurResult.hit;
  BestResult.TargetCount = CurResult.TargetCount;
  BestResult.IndexOfMax = CurResult.IndexOfMax;
  BestResult.SurroundCount = CurResult.SurroundCount;
  BestResult.TargetScore = CurResult.TargetScore;
  BestResult.SurroundScore = CurResult.SurroundScore;
  BestResult.CombinedScore = CurResult.CombinedScore;
  BestResult.x_loc = CurResult.x_loc;
  BestResult.y_loc = CurResult.y_loc;
}

void InitResult() {
  CurResult.hit = 0;
  CurResult.TargetCount = 0;
  CurResult.IndexOfMax = 0;
  CurResult.SurroundCount = 0;
  CurResult.TargetScore = 0;
  CurResult.SurroundScore = 0;
  CurResult.CombinedScore = 0;
  CurResult.x_loc = 0;
  CurResult.y_loc = 0;
} 

void ExecuteAlgorithm(t_num)
     int t_num;
{
  int startx, starty, endx, endy, x, y;
  
  startx = X - 7;
  starty = Y - 7;
  endx = X + 7;
  endy = Y + 7;

  for (y=starty; y<=endy; y++) {
    for (x=startx; x<=endx; x++) {
      InitResult();
      ExecuteOneLocation(x,y,t_num);
      CurResult.x_loc = x;
      CurResult.y_loc = y;
      if (CurResult.CombinedScore > BestResult.CombinedScore) 
	UpdateBestScore();
    }
  }
  if (BestResult.CombinedScore > CombinedThreshold) BestResult.hit = 1;
}

ComputeCombinedScore(t_num)
     int t_num;
{
  float combinedScore, targetScore, surroundScore;

  targetScore = CurResult.TargetCount * TargetScoreScaleFactor[t_num];
  surroundScore = CurResult.SurroundCount * SurroundScoreScaleFactor[t_num];
  combinedScore = targetScore + surroundScore;

  CurResult.TargetScore = targetScore;
  CurResult.SurroundScore = surroundScore;
  CurResult.CombinedScore = combinedScore;
}

void Initialize() {
  BestResult.hit = 0;
  BestResult.TargetCount = 0;
  BestResult.IndexOfMax = 0;
  BestResult.SurroundCount = 0;
  BestResult.TargetScore = 0;
  BestResult.SurroundScore = 0;
  BestResult.CombinedScore = 0;
  BestResult.x_loc = 0;
  BestResult.y_loc = 0;
}

void UpdateBestResult(void)
 {
     if (BestResult.hit) TotalHits++;
     if (BestResult.TargetCount > MaxResult.TargetCount)
	 MaxResult.TargetCount = BestResult.TargetCount;
     if (BestResult.TargetScore > MaxResult.TargetScore)
	 MaxResult.TargetScore = BestResult.TargetScore;
     if (BestResult.SurroundScore > MaxResult.SurroundScore)
	 MaxResult.SurroundScore = BestResult.SurroundScore;
     if (BestResult.CombinedScore > MaxResult.CombinedScore)
	 MaxResult.CombinedScore = BestResult.CombinedScore;
}

void PrintResults(void)
{
    printf("Total true hits = %d\n", TotalHits);
    printf("MaxTargetCount = %d\n", MaxResult.TargetCount);
    printf("MaxTargetScore = %f\n", MaxResult.TargetScore);
    printf("MaxSurroundScore = %f\n", MaxResult.SurroundScore);
    printf("MaxCombinedScore = %f\n", MaxResult.CombinedScore);
}

void main(argc, argv) 
     int argc;
     char** argv;
{
  int num;
  int num2;
  num2 = 2;

  TotalHits = 0;
  MaxResult.hit = 0;
  MaxResult.TargetCount = 0;
  MaxResult.IndexOfMax = 0;
  MaxResult.SurroundCount = 0;
  MaxResult.TargetScore = 0;
  MaxResult.SurroundScore = 0;
  MaxResult.CombinedScore = 0;
  MaxResult.x_loc = 0;
  for (num=0; num<72; num++) {
    Initialize();
    ExecuteAlgorithm(num);
    UpdateBestResult();
  }
  PrintResults();
}
